package com.jse;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;

public class Times {
	
	private static final String YMD = "yyyy-MM-dd";
	private static final String UPYMD = "yyyyMMdd";
	private static final String YMDHMS = "yyyy-MM-dd HH:mm:ss";
	private static final String YMDHMSS = "yyyy-MM-dd HH:mm:ss.SSS";
	private static final String GMT = "E, dd MMM yyyy HH:mm:ss z";
	private static final String UTC = "yyyy-MM-dd'T'HH:mm:ss'Z'";
	public static final ZoneId ZONE_ID_CN = ZoneId.of("Asia/Shanghai");
	public static final ZoneId ZONE_ID_GMT = ZoneId.of("GMT");
	public static final ZoneId ZONE_ID_UTC = ZoneId.of("UTC");
	
	private static final ConcurrentHashMap<String, DateTimeFormatter> FORMATTERS = new ConcurrentHashMap<>() {
		{put(GMT,DateTimeFormatter.ofPattern(GMT,Locale.ENGLISH).withZone(ZONE_ID_GMT));
		put(UTC,DateTimeFormatter.ofPattern(UTC,Locale.ENGLISH).withZone(ZONE_ID_UTC));
		put("GMT",get(GMT));put("gmt",get(GMT));put("UTC",get(UTC));put("utc",get(UTC));
		put(YMD,DateTimeFormatter.ofPattern(YMD).withZone(ZONE_ID_CN));
		put(YMDHMSS,DateTimeFormatter.ofPattern(YMDHMSS).withZone(ZONE_ID_CN));
		put(YMDHMS,DateTimeFormatter.ofPattern(YMDHMS).withZone(ZONE_ID_CN));
		put("HTTP",DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US).withZone(ZoneId.of("GMT")));
		}
	};
	
	public static DateTimeFormatter formats(String datePattern) {
		DateTimeFormatter ret = FORMATTERS.get(datePattern);
		if (ret == null) {
			ret = DateTimeFormatter.ofPattern(datePattern).withZone(ZONE_ID_CN);
			FORMATTERS.put(datePattern,ret);
		}
		return ret;
	}
	
	public static String format(){return format(YMDHMS);}
	public static String format(String fmt){return formats(fmt).format(Instant.now());}
	public static String format(long t){return formats(YMDHMS).format(Instant.ofEpochSecond(t));}
	public static String format(Date d){
		if(d==null)return null;
		if(d instanceof java.sql.Date x)return formats(YMD).format(x.toLocalDate());
		return formats(YMDHMS).format(d.toInstant());
	}
	public static String format(TemporalAccessor x){
		if(x instanceof LocalDate d)return formats(YMD).format(d);
		if(x instanceof LocalTime d)return formats("HH:mm:ss").format(d);
		return formats(YMDHMS).format(x);
	}
	public static String format(String fmt,TemporalAccessor d){return formats(fmt).format(d);}
	public static String format(String fmt,Date d){return formats(fmt).format(d.toInstant());}
	public static String format(Date d,String fmt){return formats(fmt).format(d.toInstant());}
	public static String format(String fmt,Number d){return formats(YMDHMS).format(Instant.ofEpochSecond(d.longValue()));}
	public static String format(String fmt,Instant d){return formats(fmt).format(d);}
	public static String format(String fmt,LocalDate d){return formats(fmt).format(d.atStartOfDay());}
	public static String format(String fmt,LocalTime d){return formats(fmt).format(d.atDate(LocalDate.now()));}

	public static String upymd(){return format(UPYMD);}
	public static String utc() {return utc(new Date());}
	public static String utc(Date d) {return format(UTC,d);}
	public static String gmt() {return gmt(new Date());}
	public static String gmt(Date date) {return format(GMT,date);}
	
	/**
	 * 格式化
	 * @param date long or date
	 * @param pattern
	 * @return
	 */
	public static Date parse(Object d) {
		if(d instanceof java.util.Date o){return o;}
		if(d instanceof Number n){return new Date(n.longValue());}
		if(d instanceof LocalDateTime l){return Date.from(l.atZone(ZoneId.systemDefault()).toInstant());}
		if(d instanceof LocalDate l){return Date.from(l.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());}
		if(d instanceof LocalTime l){return Date.from(LocalDateTime.of(LocalDate.now(), l).atZone(ZoneId.systemDefault()).toInstant());}
		if(d instanceof Instant i){return Date.from(i);}
		if(d instanceof String s) {
			if (s.length() <= 10) {
				var p=Instant.from(formats(YMD).parse(s));
				return Date.from(LocalDateTime.parse(s,formats(YMDHMS)).toInstant(ZoneOffset.of("+8")));
			} else if (s.length() > 16) {
				return Date.from(LocalDateTime.parse(s,formats(YMDHMS)).atZone(ZoneId.systemDefault()).toInstant());
			} else {
				int index = s.indexOf(':');// 判断冒号字符是否出现两次，月、日、小时、分、秒都允许是一位数，例如：2022-1-2 3:4:5
				if (index != -1) {
					if (index != s.lastIndexOf(':')) {
						return Date.from(Instant.from(formats(YMDHMS).parse(s)));
					} else {
						return Date.from(Instant.from(formats(YMDHMSS).parse(s)));
					}
				}
			}
		}
		return null;
	}

	public static LocalDateTime localDateTime(Date date) {
		if (date instanceof java.sql.Date) {date = new Date(date.getTime());}
		return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
	}
	
	
	public static String toString(Date d) {
		if(d instanceof java.sql.Date sd) {
			
		}else if(d instanceof java.sql.Time sd) {
			
		}
		return format(d);
	}
	
	
	public static void main(String[] args) {
		var d=new Date();
		String gmt=gmt(d);
		System.out.println(gmt);
		System.out.println(format());
		System.out.println(new Date());
		System.out.println(LocalDateTime.now());
		System.out.println(new Date().toLocaleString());
		System.out.println(new Date().toGMTString());
		System.out.println(gmt());
		
	}

	
}
